﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security;
using System.Text;
using System.Threading;
using Microsoft.ApplicationServer.Caching;
using DevToolBox.Common;
using DevToolBox.Cloud.Common;


namespace DevToolBox.Cloud.Azure
{
    /// <summary>
    /// Class to abstract the interatcion with the Azure Cache
    /// </summary>
    public class WindowsAzureSharedCaching: ICacheable
    {
        DataCache dataCache = null;

        /// <summary>
        /// Default constructor
        /// </summary>
        /// <remarks>
        /// This method need that the following parameters exist in the configuration file:
        /// AzureUrl, AzurePort and AzureToken.
        /// Windows Azure Caching (from role) != Windows Azure Shared Caching
        /// </remarks>
        public WindowsAzureSharedCaching()
        {
            string host = ConfigParamReader.GetString("AzureUrl");
            int port = ConfigParamReader.GetInt32("AzurePort");
            string token = ConfigParamReader.GetString("AzureToken");

            SecureString authorizationToken = new SecureString();
            foreach (char c in token)
            {
                authorizationToken.AppendChar(c);
            }

            List<DataCacheServerEndpoint> servers = new List<DataCacheServerEndpoint>();
            servers.Add(new DataCacheServerEndpoint(host, port));
            DataCacheFactoryConfiguration conf = new DataCacheFactoryConfiguration();
            conf.SecurityProperties = new DataCacheSecurity(authorizationToken);
            conf.ChannelOpenTimeout = TimeSpan.FromMinutes(10);
            conf.RequestTimeout = TimeSpan.FromMinutes(10);
            conf.Servers = servers;
            conf.TransportProperties.MaxBufferSize = 2147483647;
            conf.TransportProperties.ChannelInitializationTimeout = TimeSpan.FromMinutes(10);

            DataCacheFactory dataCacheFactory = new DataCacheFactory(conf);
            dataCache = dataCacheFactory.GetDefaultCache();
        }

        /// <summary>
        /// Method to add an item to the Azure Cache Service
        /// </summary>
        /// <param name="key">Item key</param>
        /// <param name="value">Item value</param>
        public void Set(string key, object value)
        {
            if (dataCache != null && key != null)
            {
                //06-FEB-2013: previously the Add method was used
                //in combination with Get but for increasing performance
                //was changed to Put. See: http://bit.ly/TICl6d                
                int curFailedAttempts = 0;
                int maxFailedAttempts = 3;
                bool doEval = true;

                while (curFailedAttempts < maxFailedAttempts && doEval)
                {
                    try
                    {
                        dataCache.Put(key, value);
                        doEval = false;
                    }
                    catch (Exception ex)
                    {
                        curFailedAttempts++;
                        if (curFailedAttempts >= maxFailedAttempts)
                        {
                            return;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Method to retrieve an item from the Azure Cache Service
        /// </summary>
        /// <param name="key">Item Key</param>
        /// <returns>Item value</returns>
        public object Get(string key)
        {
            if (dataCache == null || key == null) return null;
            object obj = null;

            int curFailedAttempts = 0;
            int maxFailedAttempts = 3;
            bool doEval = true;

            while (curFailedAttempts < maxFailedAttempts && doEval)
            {
                try
                {
                    obj = dataCache.Get(key);
                    doEval = false;
                }
                catch (Exception ex)
                {
                    curFailedAttempts++;
                }
            }

            return obj;
        }

    }
}
